package com.geoai.uimap.core.mapbox

import android.graphics.Bitmap
import android.view.View
import com.geoai.uimap.api.GEOMapMarker
import com.geoai.uimap.api.IGEOMap
import com.geoai.uimap.core.mapbox.markerview.NewMarkerView
import com.geoai.uimap.geo.ILatLng
import com.geoai.uimap.utils.dpToPx
import com.geoai.uimap.utils.getMapBoxGeometry
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.plugins.annotation.Symbol
import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import com.mapbox.mapboxsdk.utils.BitmapUtils

class MapboxMarker(private val map: IGEOMap) : GEOMapMarker() {

    private var mSymbol: Symbol? = null
    private var mMarkerView: NewMarkerView? = null
    private var mSymbolManager: SymbolManager? = null
    override fun show(): GEOMapMarker {
        if (markerPoint == null || (mImageResId == -1 && mImageBitmap == null)) return this
        val style = map.getMapBoxGeometry()?.getStyle() ?: return this
        style.let { style ->
            val bitmapName: String
            val bitmapSource: Bitmap

            if (mImageBitmap != null) {
                bitmapName = mImageBitmap!!.hashCode().toString()
                bitmapSource = mImageBitmap!!
            } else {
                bitmapName = mImageResId.toString()
                bitmapSource = BitmapUtils.getBitmapFromDrawable(map.getContext().resources.getDrawable(mImageResId))!!
            }
            if (style.getImage(bitmapName) == null) {
                style.addImage(bitmapName, bitmapSource)
                invokeSymbolList(style, bitmapName, bitmapSource)
            }
        }
        mSymbolManager = if (mTop) map.getMapBoxGeometry()?.getTopSymbolManager() else map.getMapBoxGeometry()?.getSymbolManager()
        mSymbolManager?.let {
            var sortKey = -1f
            if (!it.annotations.isEmpty && it.annotations.size() > 0) {
                sortKey = it.annotations.valueAt(it.annotations.size() - 1)?.id?.toFloat() ?: -1f
            }
            val symbolOptions = SymbolOptions()
                .withLatLng(LatLng(markerPoint!!.latitude, markerPoint!!.longitude))
                .withIconImage(mImageBitmap?.hashCode()?.toString() ?: mImageResId.toString())
                .withIconRotate(mAngel)
                .withSymbolSortKey(sortKey)
            mSymbol = it.create(symbolOptions)
        }
        return this
    }

    override fun setRotateAngle(angel: Float): GEOMapMarker {
        mAngel = angel
        mSymbol?.let {
            it.iconRotate = angel
            mSymbolManager?.update(it)
        }
        return this
    }

    override fun setImageId(resId: Int): GEOMapMarker {
        mImageResId = resId
        map.getMapBoxGeometry()?.getStyle()?.let {
            val bitmapDrawable = BitmapUtils.getBitmapFromDrawable(map.getContext().resources.getDrawable(mImageResId))
            it.getImage(mImageResId.toString()) ?: {
                it.addImage(mImageResId.toString(), bitmapDrawable!!)
                invokeSymbolList(it, mImageResId.toString(), bitmapDrawable!!)
            }
        }
        mSymbol?.let {
            it.iconImage = mImageResId.toString()
            mSymbolManager?.update(it)
        }
        return this
    }

    override fun setImage(resId: Bitmap?): GEOMapMarker {
        resId?.let {
            mImageBitmap = resId
            map.getMapBoxGeometry()?.getStyle()?.let {
                it.addImage(resId.hashCode().toString(), resId)
                invokeSymbolList(it, resId.hashCode().toString(), resId)
            }
            mSymbol?.let {
                it.iconImage = resId.hashCode().toString()
                mSymbolManager?.update(it)
            }
        }
        return this
    }

    override fun setToTop(top: Boolean): GEOMapMarker {
        mTop = top
        return this
    }

    override fun setPosition(position: ILatLng): GEOMapMarker {
        markerPoint = position
        mSymbol?.let {
            it.latLng = LatLng(position.latitude, position.longitude)
            mSymbolManager?.update(it)
        }
        return this
    }


    override fun destroy() {
        mSymbol?.let {
            mSymbolManager?.delete(it)
        }
        mMarkerView?.let {
            map.getMapBoxGeometry()?.getMarkerViewManager()?.removeMarker(it)
        }
    }

    override fun showInfoWindow(): GEOMapMarker {
        if (map is MapboxImpl) {
            val newView = map.getInfoWindowAdapter()?.getInfoWindow(getMarkerId())
            if (newView != null && markerPoint != null) {
                mMarkerView = NewMarkerView(LatLng(markerPoint!!.latitude, markerPoint!!.longitude), newView)
//                mMarkerView?.setOffset(-100f, -80f)
                val width: Int = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
                val height: Int = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
                newView.measure(width, height)
                mMarkerView?.setOffset(-(newView.measuredWidth / 2).toFloat(), -(dpToPx(20f) + newView.measuredHeight))
                map.getGeometryManager()?.getMarkerViewManager()?.addMarker(mMarkerView!!)
            }
        }
        return this
    }

    override fun hideInfoWindow() {
        if (map is MapboxImpl) {
            mMarkerView?.let { map.getGeometryManager()?.getMarkerViewManager()?.removeMarker(it) }
        }
    }


    override fun getMarkerId(): String {
        return mSymbol?.id.toString()
    }

    private fun invokeSymbolList(style: Style, bitmapName: String, bitmapSource: Bitmap) {
        //将资源放置在style中保管，避免切换图源导致的marker丢失
        with(style.javaClass.getDeclaredField("images")) {
            isAccessible = true
            get(style) as HashMap<String, Bitmap>
        }[bitmapName] = bitmapSource
    }
}